#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include "Thread.hpp"
#include "MyMutex.hpp"
#include "CondVal.hpp"


namespace BlockQueueArea
{
    using namespace MyThread;
    using namespace CondValArea;
    using namespace MyMutexArea;
    

    template<class T>
    class MyBlockQueue
    {
    private:
        bool IsFull()
        {
            return _qu.size()==_cap;
        }

        bool IsEmpty()
        {
            return _qu.empty();
        }
    public:
        MyBlockQueue(int cap):_cap(cap),_producer_wait(0),_consumer_wait(0)
        {}

        void Push(const T& data)//生产
        { 
            _mutex.Lock();//加锁
            while(IsFull())//队列满了，让消费者拿，生产者等待
            {
                printf("生产者进入等待...\n");
                _producer_wait++;
                _producer_cond.PthreadWait(_mutex);
                _producer_wait--;
                printf("生产者被唤醒...\n");
            }
            _qu.push(data);
            printf("生产了一个数据: %d\n",data);

            if(_consumer_wait)//生产数据后,唤醒消费者线程
                _consumer_cond.PthreadSignal();
            
            _mutex.UnLock();//解锁
        }

        void Pop()//消费
        {
            _mutex.Lock();//加锁
            while(IsEmpty())//队列为空，让生产者生产，消费者等待
            {
                printf("消费者进入等待...\n");
                _consumer_wait++;
                _consumer_cond.PthreadWait(_mutex);//等待
                _consumer_wait--;
                printf("消费者被唤醒...\n");
            }
            printf("消费了一个数据: %d\n",_qu.front());
            _qu.pop();

            if(_producer_wait)//消费数据后,唤醒生产者线程
                _producer_cond.PthreadSignal();

            _mutex.UnLock();//解锁
        }


        ~MyBlockQueue()
        {}

    private:
        std::queue<T> _qu;//存储数据的底层容器
        MyMutex _mutex;//锁
        MyCondVal _producer_cond;//给生产者提供的条件变量
        MyCondVal _consumer_cond;//给消费者提供的条件变量
        int _cap;//队列最大容量
        int _producer_wait;//等待的生产线程数量
        int _consumer_wait;//等待的消费线程数量

    };
};